home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / lib / mk_html_help.pro < prev    next >
Text File  |  1997-07-08  |  19KB  |  570 lines

  1. ; $Id: mk_html_help.pro,v 1.8 1997/01/15 03:11:50 ali Exp $
  2. ;
  3. ; Copyright (c) 1995-1997, Research Systems, Inc.  All rights reserved.
  4. ;       Unauthorized reproduction prohibited.
  5. ;+
  6. ; NAME:
  7. ;    MK_HTML_HELP
  8. ;
  9. ; PURPOSE:
  10. ;    Given a list of IDL procedure files (.PRO), VMS text library 
  11. ;       files (.TLB), or directories that contain such files, this procedure 
  12. ;       generates a file in the HTML format that contains the documentation 
  13. ;       for those routines that contain a DOC_LIBRARY style documentation 
  14. ;       template.  The output file is compatible with World Wide Web browsers.
  15. ;
  16. ; CATEGORY:
  17. ;    Help, documentation.
  18. ;
  19. ; CALLING SEQUENCE:
  20. ;    MK_HTML_HELP, Sources, Outfile
  21. ;
  22. ; INPUTS:
  23. ;     Sources:  A string or string array containing the name(s) of the
  24. ;        .pro or .tlb files (or the names of directories containing 
  25. ;               such files) for which help is desired.  If a source file is 
  26. ;               a VMS text library, it must include the .TLB file extension.  
  27. ;               If a source file is an IDL procedure, it must include the .PRO
  28. ;               file extension.  All other source files are assumed to be
  29. ;               directories.
  30. ;     Outfile:    The name of the output file which will be generated.
  31. ;
  32. ; KEYWORDS:
  33. ;     TITLE:    If present, a string which supplies the name that
  34. ;        should appear as the Document Title for the help.
  35. ;     VERBOSE:    Normally, MK_HTML_HELP does its work silently.
  36. ;        Setting this keyword to a non-zero value causes the procedure
  37. ;        to issue informational messages that indicate what it
  38. ;        is currently doing. !QUIET must be 0 for these messages
  39. ;               to appear.
  40. ;     STRICT:   If this keyword is set to a non-zero value, MK_HTML_HELP will 
  41. ;               adhere strictly to the HTML format by scanning the 
  42. ;               the document headers for characters that are reserved in 
  43. ;               HTML (<,>,&,").  These are then converted to the appropriate 
  44. ;               HTML syntax in the output file. By default, this keyword
  45. ;               is set to zero (to allow for faster processing).
  46. ;
  47. ; COMMON BLOCKS:
  48. ;    None.
  49. ;
  50. ; SIDE EFFECTS:
  51. ;    A help file with the name given by the Outfile argument is
  52. ;    created.
  53. ;
  54. ; RESTRICTIONS:
  55. ;    The following rules must be followed in formatting the .pro
  56. ;    files that are to be searched.
  57. ;        (a) The first line of the documentation block contains
  58. ;            only the characters ";+", starting in column 1.
  59. ;               (b) There must be a line which contains the string "NAME:",
  60. ;                   which is immediately followed by a line containing the
  61. ;                   name of the procedure or function being described in
  62. ;                   that documentation block.  If this NAME field is not
  63. ;                   present, the name of the source file will be used.
  64. ;        (c) The last line of the documentation block contains
  65. ;            only the characters ";-", starting in column 1.
  66. ;        (d) Every other line in the documentation block contains
  67. ;            a ";" in column 1.
  68. ;
  69. ;       Note that a single .pro file can contain multiple procedures and/or
  70. ;       functions, each with their own documentation blocks. If it is desired
  71. ;       to have "invisible" routines in a file, i.e. routines which are only
  72. ;       for internal use and should not appear in the help file, simply leave
  73. ;       out the ";+" and ";-" lines in the documentation block for those
  74. ;       routines.
  75. ;
  76. ;    No reformatting of the documentation is done.
  77. ;
  78. ; MODIFICATION HISTORY:
  79. ;       July 5, 1995, DD, RSI. Original version.
  80. ;       July 13, 1995, Mark Rivers, University of Chicago. Added support for
  81. ;               multiple source directories and multiple documentation
  82. ;               headers per .pro file.
  83. ;       July 17, 1995, DD, RSI. Added code to alphabetize the subjects;
  84. ;               At the end of each description block in the HTML file,
  85. ;               added a reference to the source .pro file.
  86. ;       July 18, 1995, DD, RSI. Added STRICT keyword to handle angle brackets.
  87. ;       July 19, 1995, DD, RSI. Updated STRICT to handle & and ".
  88. ;               Changed calling sequence to accept .pro filenames, .tlb
  89. ;               text librarie names, and/or directory names.
  90. ;               Added code to set default subject to name of file if NAME
  91. ;               field is not present in the doc header.
  92. ;
  93. ;-
  94. ;
  95.  
  96. ;----------------------------------------------------------------------------
  97. PRO mhh_strict, txtlines
  98. ;
  99. ; Replaces any occurrence of HTML reserved characters (<,>,&,") in the
  100. ; given text lines with the appropriate HTML counterpart.
  101. ;
  102. ; entry:
  103. ;       txtlines - String array containing the text line(s) to be altered.
  104. ; exit:
  105. ;    txtlines - Same as input except that reserved characters have been 
  106. ;                  replaced with the appropriate HTML syntax.
  107. ;
  108.  count = N_ELEMENTS(txtlines)
  109.  FOR i=0,count-1 DO BEGIN
  110.   txt = txtlines[i] 
  111.  
  112.   ; Ampersands get replaced with &.  Must do ampersands first because
  113.   ; they are used to replace other reserved characters in HTML.
  114.   spos = STRPOS(txt,'&')
  115.   WHILE (spos NE -1) DO BEGIN
  116.    newtxt = STRMID(txt,0,spos)+'&'+STRMID(txt,spos+1,STRLEN(txt)-spos+1)
  117.    txt = newtxt
  118.    spos = STRPOS(txt,'&',spos+1)
  119.   ENDWHILE
  120.   txtlines[i] = txt
  121.  
  122.   ; Left angle brackets get replaced with <
  123.   spos = STRPOS(txt,'<')
  124.   WHILE (spos NE -1) DO BEGIN
  125.    newtxt = STRMID(txt,0,spos)+'<'+STRMID(txt,spos+1,STRLEN(txt)-spos+1)
  126.    txt = newtxt
  127.    spos = STRPOS(txt,'<',spos+1)
  128.   ENDWHILE
  129.   txtlines[i] = txt
  130.  
  131.   ; Right angle brackets get replaced with >
  132.   spos = STRPOS(txt,'>')
  133.   WHILE (spos NE -1) DO BEGIN
  134.    newtxt = STRMID(txt,0,spos)+'>'+STRMID(txt,spos+1,STRLEN(txt)-spos+1)
  135.    txt = newtxt
  136.    spos = STRPOS(txt,'>',spos+1)
  137.   ENDWHILE
  138.   txtlines[i] = txt
  139.  
  140.   ; Double quotes get replaced with "
  141.   spos = STRPOS(txt,'"')
  142.   WHILE (spos NE -1) DO BEGIN
  143.    newtxt = STRMID(txt,0,spos)+'"'+STRMID(txt,spos+1,STRLEN(txt)-spos+1)
  144.    txt = newtxt
  145.    spos = STRPOS(txt,'"',spos+1)
  146.   ENDWHILE
  147.   txtlines[i] = txt
  148.  ENDFOR
  149. END
  150.  
  151. ;----------------------------------------------------------------------------
  152. PRO  mhh_grab_hdr,name,dict,infile_indx,libfile_indx,txt_file,verbose,$
  153.      strict
  154. ;
  155. ; Searches an input file for all text between the ;+ and ;- comments, and
  156. ; updates the scratch text file appropriately. Note that this routine
  157. ; will extract multiple comment blocks from a single source file if they are
  158. ; present.
  159. ;
  160. ; entry:
  161. ;    name - Name of file containing documentation header(s).
  162. ;       dict[] - Dictionary entries for each documentation block in the .PRO
  163. ;               file.  Each dictionary entry is a structure with an index to 
  164. ;               the source filename, an index to the extracted library 
  165. ;               filename (useful only for VMS text libraries), a subject name,
  166. ;               scratch file offset, unique id (for duplicate names), and 
  167. ;               number of lines of documentation text.  
  168. ;               This parameter may be originally undefined at entry.
  169. ;       infile_indx - Index of the source .pro or .tlb filename.
  170. ;       libfile_indx - Index of extracted library filename.  If the source
  171. ;               filename was not a VMS text library, this value should be
  172. ;               set to -1L. 
  173. ;    txt_file - Scratch file to which the documentation header will
  174. ;               be written.
  175. ;    verbose - TRUE if the routine should output a descriptive message
  176. ;        when it finds the documentation header.
  177. ;       strict - If nonzero, the routine will adhere strictly to HTML format.
  178. ;                The document headers will be scanned for characters that are
  179. ;                reserved in HTML (<,>,&,"), which are then converted to the 
  180. ;                appropriate HTML syntax in the output file.
  181. ;
  182. ; exit:
  183. ;    txt_file -  Updated as necessary. Positioned at EOF.
  184. ;       dict[] - Updated array of new dictionary entries.
  185. ;
  186.  
  187.  ; Under DOS, formatted output ends up with a carriage return linefeed
  188.  ; pair at the end of every record. The resulting file would not be
  189.  ; compatible with Unix. Therefore, we use unformatted output, and
  190.  ; explicity add the linefeed, which has ASCII value 10.
  191.  LF=10B
  192.  
  193.  IF (libfile_indx NE -1L) THEN $
  194.   OPENR, in_file, /GET, FILEPATH('mkhtmlhelp.scr',/TMP), /DELETE $
  195.  ELSE $
  196.   OPENR, in_file, /GET, name
  197.  
  198.  IF (verbose NE 0) THEN MESSAGE,/INFO, 'File = '+name
  199.  WHILE (1) DO BEGIN
  200.   ; Find the opening line of the next header.
  201.   tmp = ''
  202.   found = 0
  203.   num = 0
  204.   header = ''
  205.   ON_IOERROR, DONE
  206.   WHILE (NOT found) DO BEGIN
  207.    READF, in_file, tmp
  208.    IF (STRMID(tmp,0,2) EQ ';+') THEN found = 1
  209.   ENDWHILE
  210.  
  211.   IF (found) THEN BEGIN
  212.    ; Find the matching closing line of the header.
  213.    found = 0
  214.    WHILE (NOT found) DO BEGIN
  215.     READF,in_file,tmp
  216.     IF (STRMID(tmp,0,2) EQ ';-') THEN BEGIN
  217.      found =1
  218.     ENDIF ELSE BEGIN
  219.      tmp = strmid(tmp, 1, 1000)
  220.      header = [header, tmp]
  221.      num = num + 1
  222.     ENDELSE
  223.    ENDWHILE
  224.  
  225.    IF (strict) THEN mhh_strict,header
  226.    ; Done with one block of header
  227.  
  228.    ; Keep track of current scratch file offset, then write doc text.
  229.    POINT_LUN,-txt_file,pos
  230.    FOR i=1, num DO BEGIN
  231.     WRITEU, txt_file, header[i],LF
  232.    ENDFOR
  233.  
  234.    ; Search for the subject. It is the line following name.
  235.    index = WHERE(STRTRIM(header, 2) EQ 'NAME:', count)
  236.    IF (count eq 1) THEN BEGIN
  237.     sub = STRUPCASE(STRTRIM(header[index[0]+1], 2))
  238.     IF (verbose NE 0) THEN MESSAGE,/INFO, 'Routine = '+sub
  239.  
  240.    ; If the NAME field was not present, set the subject to the name of the 
  241.    ; source text file.
  242.    ENDIF ELSE BEGIN
  243.     MESSAGE,/INFO,'Properly formatted NAME entry not found...'
  244.     ifname = name
  245.  
  246.     CASE !VERSION.OS_FAMILY OF
  247.      'Windows': tok = '\'
  248.      'MacOS': tok = ':'
  249.      ELSE: tok = '/'
  250.     ENDCASE
  251.  
  252.     ; Cut the path.
  253.     sp0 = 0
  254.     spos = STRPOS(ifname,tok,sp0)
  255.     WHILE (spos NE -1) DO BEGIN
  256.      sp0 = spos+1
  257.      spos = STRPOS(ifname,tok,sp0)
  258.     ENDWHILE
  259.     ifname = STRMID(ifname,sp0,(STRLEN(ifname)-sp0))
  260.  
  261.     ; Cut the suffix.
  262.     spos = STRPOS(ifname,'.')
  263.     IF (spos NE -1) THEN ifname = STRMID(ifname,0,spos[0])
  264.     IF (strict) THEN mhh_strict, ifname
  265.     sub = STRUPCASE(ifname)
  266.     MESSAGE,/INFO,'  Setting subject to filename: '+sub+'.'
  267.    ENDELSE
  268.  
  269.    ; Calculate unique id in case of duplicate subject names.
  270.    IF (N_ELEMENTS(dict) EQ 0) THEN $
  271.     ndup=0 $
  272.    ELSE BEGIN
  273.     dpos = WHERE(dict.subject EQ sub,ndup)
  274.     IF (ndup EQ 1) THEN BEGIN
  275.      dict[dpos[0]].id = 1
  276.      ndup = ndup + 1
  277.     ENDIF
  278.    ENDELSE
  279.  
  280.    ; Create a dictionary entry for the document header.
  281.    entry = {DICT_STR,subject:sub,indx:infile_indx,lib:libfile_indx,$
  282.             id:ndup,offset:pos,nline:num}
  283.    IF (N_ELEMENTS(dict) EQ 0) THEN dict = [entry] ELSE dict = [dict,entry]
  284.   ENDIF
  285.  ENDWHILE
  286.  
  287. DONE: 
  288.  ON_IOERROR, NULL
  289.  FREE_LUN, in_file
  290. END
  291.  
  292. ;----------------------------------------------------------------------------
  293. PRO mhh_gen_file,dict,txt_file,infiles,libfiles,outfile,verbose,title,strict
  294. ;
  295. ; Build a .HTML file with the constituent parts.
  296. ;
  297. ; entry:
  298. ;       dict - Array of dictionary entries. Each entry is a structure
  299. ;              with a subject name, scratch file offset, number of lines
  300. ;              of documentation text, etc.
  301. ;       infiles - String array containing the name(s) of .pro or .tlb files 
  302. ;              for which help is being generated.
  303. ;       libfiles - String array containing the name(s) of .pro files extracted
  304. ;              from any .tlb files in the infiles array. 
  305. ;    txt_file - Scratch file containing the documentation text.
  306. ;    outfile - NAME of final HELP file to be generated.
  307. ;    verbose - TRUE if the routine should output a descriptive message
  308. ;        when it finds the documentation header.
  309. ;    title - Scalar string containing the name to go at the top of the
  310. ;               HTML help page.
  311. ;       strict - If nonzero, the routine will adhere strictly to HTML format.
  312. ;                The document headers will be scanned for characters that are
  313. ;                reserved in HTML (<,>,&,"), which are then converted to the 
  314. ;                appropriate HTML syntax in the output file.
  315. ;
  316. ; exit:
  317. ;    outfile has been created.
  318. ;    txt_file has been closed via FREE_LUN.
  319. ;
  320.  
  321.  ; Append unique numbers to any duplicate subject names.
  322.  dpos = WHERE(dict.id GT 0,ndup) 
  323.  FOR i=0,ndup-1 DO BEGIN
  324.   entry = dict[dpos[i]]
  325.   dict[dpos[i]].subject = entry.subject+'['+STRTRIM(STRING(entry.id),2)+']'
  326.  ENDFOR
  327.  
  328.  ; Sort the subjects alphabetically.
  329.  count = N_ELEMENTS(dict)
  330.  indices = SORT(dict.subject)
  331.  
  332.  ; Open the final file.
  333.  OPENW,final_file,outfile,/STREAM,/GET_LUN
  334.  IF (verbose NE 0) THEN MESSAGE,/INFO,'Building '+outfile+'...'
  335.  
  336.  ; Print a comment indicating how the file was generated.
  337.  PRINTF,final_file,'<!-- This file was generated by mk_html_help.pro -->'
  338.  
  339.  ; Header stuff.
  340.  PRINTF,final_file,'<html>'
  341.  PRINTF,final_file,' '
  342.  
  343.  ; Title.
  344.  PRINTF,final_file,'<head>'
  345.  PRINTF,final_file,'<TITLE>',title,'</TITLE>
  346.  PRINTF,final_file,'</head>'
  347.  PRINTF,final_file,' '
  348.  
  349.  ; Title and intro info.
  350.  PRINTF,final_file,'<body>'
  351.  PRINTF,final_file,'<H1>',title,'</H1>'
  352.  PRINTF,final_file,'<P>'
  353.  PRINTF,final_file,'This page was created by the IDL library routine '
  354.  PRINTF,final_file,'<CODE>mk_html_help</CODE>.  For more information on '
  355.  PRINTF,final_file,'this routine, refer to the IDL Online Help Navigator '
  356.  PRINTF,final_file,'or type: <P>'
  357.  PRINTF,final_file,'<PRE>     ? mk_html_help</PRE><P>'
  358.  PRINTF,final_file,'at the IDL command line prompt.<P>'
  359.  PRINTF,final_file,'<STRONG>Last modified: </STRONG>',SYSTIME(),'.<P>'
  360.  PRINTF,final_file,' '
  361.  PRINTF,final_file,'<HR>'
  362.  PRINTF,final_file,' '
  363.  
  364.  ; Index.
  365.  PRINTF,final_file,'<A NAME="ROUTINELIST">'
  366.  PRINTF,final_file,'<H1>List of Routines</H1></A>'
  367.  PRINTF,final_file,'<UL>'
  368.  FOR i=0,count-1 DO BEGIN
  369.   entry = dict[indices[i]]
  370.  
  371.   IF (entry.nline GT 0) THEN $
  372.    PRINTF,final_file,'<LI><A HREF="#',entry.subject,'">',entry.subject,'</A>'
  373.  ENDFOR
  374.  PRINTF,final_file,'</UL><P>'
  375.  PRINTF,final_file,' '
  376.  
  377.  PRINTF,final_file,'<HR>'
  378.  PRINTF,final_file,' '
  379.  
  380.  ; Descriptions.
  381.  PRINTF,final_file,'<H1>Routine Descriptions</H1>'
  382.  ON_IOERROR,TXT_DONE
  383.  FOR i=0,count-1 DO BEGIN
  384.   entry = dict[indices[i]]
  385.   IF (entry.nline GT 0) THEN BEGIN
  386.    PRINTF,final_file,'<A NAME="',entry.subject,'">'
  387.    PRINTF,final_file,'<H2>',entry.subject,'</H2></A>'
  388.  
  389.    prev_i = i - 1
  390.    IF (prev_i LT 0) THEN $
  391.     dostep = 0 $ 
  392.    ELSE BEGIN
  393.     prev_ent = dict[indices[prev_i]]
  394.     dostep = prev_ent.nline EQ 0
  395.    ENDELSE
  396.    WHILE dostep DO BEGIN
  397.     prev_i = prev_i - 1
  398.     IF (prev_i LT 0) THEN $
  399.      dostep = 0 $
  400.     ELSE BEGIN
  401.      prev_ent = dict[indices[prev_i]]
  402.      dostep = prev_ent.nline EQ 0
  403.     ENDELSE
  404.    ENDWHILE
  405.    IF (prev_i GE 0) THEN $
  406.     PRINTF,final_file,'<A HREF="#',prev_ent.subject,'">[Previous Routine]</A>'
  407.  
  408.    next_i = i + 1
  409.    IF (next_i GE count) THEN $
  410.     dostep = 0 $
  411.    ELSE BEGIN
  412.     next_ent = dict[indices[next_i]]
  413.     dostep = next_ent.nline EQ 0
  414.    ENDELSE
  415.    WHILE dostep DO BEGIN
  416.     next_i = next_i + 1
  417.     IF (next_i GE count) THEN $
  418.      dostep = 0 $
  419.     ELSE BEGIN
  420.      next_ent = dict[indices[next_i]]
  421.      dostep = next_ent.nline EQ 0
  422.     ENDELSE
  423.    ENDWHILE
  424.    IF (next_i LT count) THEN $
  425.     PRINTF,final_file,'<A HREF="#',next_ent.subject,'">[Next Routine]</A>'
  426.  
  427.    PRINTF,final_file,'<A HREF="#ROUTINELIST">[List of Routines]</A>'
  428.    PRINTF,final_file,'<PRE>'
  429.    tmp = ''
  430.  
  431.    POINT_LUN,txt_file,entry.offset
  432.    FOR j=1,entry.nline DO BEGIN
  433.     READF,txt_file,tmp
  434.     PRINTF,final_file,tmp
  435.    ENDFOR
  436.    PRINTF,final_file,'</PRE><P>'
  437.    IF (entry.lib NE -1L) THEN BEGIN
  438.     fname = libfiles[entry.lib]
  439.     lname = infiles[entry.indx]
  440.     IF (strict) THEN BEGIN
  441.      mhh_strict,fname
  442.      mhh_strict,lname
  443.     ENDIF
  444.     PRINTF,final_file,'<STRONG>(See '+fname+' in '+lname+')</STRONG><P>'
  445.    ENDIF ELSE BEGIN
  446.     fname = infiles[entry.indx]
  447.     IF (strict) THEN mhh_strict,fname
  448.     PRINTF,final_file,'<STRONG>(See '+fname+')</STRONG><P>'
  449.    ENDELSE
  450.    PRINTF,final_file,'<HR>'
  451.    PRINTF,final_file,' '
  452.   ENDIF
  453.  ENDFOR
  454. TXT_DONE:
  455.  ON_IOERROR,NULL
  456.  FREE_LUN,txt_file
  457.  
  458.  ; Footer.
  459.  PRINTF,final_file,'</body>'
  460.  PRINTF,final_file,'</html>'
  461.  FREE_LUN,final_file
  462. END
  463.  
  464. ;----------------------------------------------------------------------------
  465. PRO mk_html_help, sources, outfile, VERBOSE=verbose, TITLE=title, STRICT=strict
  466.  
  467.  IF (NOT KEYWORD_SET(verbose)) THEN verbose=0
  468.  IF (NOT KEYWORD_SET(title)) THEN title="Extended IDL Help" 
  469.  IF (NOT KEYWORD_SET(strict)) THEN strict=0
  470.  
  471.  infiles = ''
  472.  istlb = 0b
  473.  
  474.  count = N_ELEMENTS(sources)
  475.  IF (count EQ 0) THEN BEGIN
  476.   MESSAGE,/INFO,'No source IDL directories found.'
  477.   RETURN
  478.  ENDIF
  479.  
  480.  ; Open a temporary file for the documentation text.
  481.  OPENW, txt_file, FILEPATH('userhtml.txt', /TMP), /STREAM, /GET_LUN, /DELETE
  482.  
  483.  ; Loop on sources. 
  484.  FOR i=0, count-1 DO BEGIN
  485.   src = sources[i]
  486.  
  487.   ; Strip any version numbers from the source so we can check for the
  488.   ; VMS .tlb or .pro extension.
  489.   vpos = STRPOS(src,';')
  490.   IF (vpos NE -1) THEN vsource = STRMID(src,0,vpos) ELSE vsource = src
  491.  
  492.    ; Test if the source is a VMS text library.
  493.   IF (!VERSION.OS EQ 'vms') AND (STRLEN(vsource) GT 4) AND $
  494.      (STRUPCASE(STRMID(vsource, STRLEN(vsource)-4,4)) EQ '.TLB') THEN BEGIN 
  495.    infiles = [infiles,src]
  496.    istlb = [istlb, 1b]
  497.   ENDIF ELSE BEGIN
  498.    ; Test if the file is a .PRO file.
  499.    IF (STRUPCASE(STRMID(vsource, STRLEN(vsource)-4,4)) EQ '.PRO') THEN BEGIN 
  500.     infiles = [infiles,src]
  501.     istlb = [istlb, 0b]
  502.  
  503.    ; If not a VMS text library or .PRO file, it must be a directory name.
  504.    ENDIF ELSE BEGIN
  505.     CASE !VERSION.OS_FAMILY OF
  506.      'Windows': tok = '\'
  507.      'MacOS': tok = ':'
  508.      'unix': tok = '/'
  509.      'vms': tok = ''
  510.     ENDCASE
  511.  
  512.     ; Get a list of all .pro files in the directory.
  513.     flist = FINDFILE(src+tok+'*.pro',COUNT=npro)
  514.     IF (npro GT 0) THEN BEGIN
  515.      infiles = [infiles,flist]
  516.      istlb = [istlb, REPLICATE(0b,npro)]
  517.     ENDIF
  518.  
  519.     ; Get a list of all .tlb files in the directory.
  520.     flist = FINDFILE(src+tok+'*.tlb',COUNT=ntlb)
  521.     IF (ntlb GT 0) THEN BEGIN
  522.      infiles = [infiles,flist]
  523.      istlb = [istlb, REPLICATE(1b,ntlb)]
  524.     ENDIF
  525.    ENDELSE
  526.   ENDELSE
  527.  ENDFOR
  528.  
  529.  count = N_ELEMENTS(infiles)
  530.  IF (count EQ 1) THEN BEGIN
  531.   MESSAGE,/INFO,'No IDL files found.'
  532.   RETURN
  533.  ENDIF 
  534.  infiles = infiles[1:*]
  535.  istlb = istlb[1:*]
  536.  count = count-1
  537.  
  538.  ; Loop on all files.
  539.  FOR i=0,count-1 DO BEGIN
  540.   src = infiles[i]
  541.  
  542.   IF (istlb[i]) THEN BEGIN
  543.    ; If it is a text library, get a list of routines by spawning
  544.    ; a LIB/LIST command. 
  545.    SPAWN,'LIBRARY/TEXT/LIST ' + src,files
  546.    lib_count = N_ELEMENTS(files)
  547.    j=0
  548.    WHILE ((j LT lib_count) AND (STRLEN(files[j]) NE 0)) DO j = j + 1
  549.    lib_count = lib_count - j - 1
  550.    IF (count GT 0) THEN files = files[j+1:*]
  551.    ; We do a separate extract for each potential routine. This is
  552.    ; pretty slow, but easy to implement. This routine is generally
  553.    ; run once in a long while, so I think it's OK.
  554.    lib_total = N_ELEMENTS(libfiles)
  555.    IF (lib_total EQ 0) THEN libfiles = files ELSE libfiles = [libfiles, files]
  556.    FOR j=0, lib_count-1 DO BEGIN
  557.     name = FILEPATH('mkhtmlhelp.scr',/TMP)
  558.     SPAWN,'LIBRARY/TEXT/EXTRACT='+files[j]+'/OUT='+name+' '+src
  559.     mhh_grab_hdr,files[j],dict,i,lib_total+j,txt_file,verbose,strict
  560.    ENDFOR
  561.   ENDIF ELSE BEGIN
  562.    name = infiles[i]
  563.    mhh_grab_hdr,name,dict,i,-1L,txt_file,verbose,strict
  564.   ENDELSE
  565.  ENDFOR
  566.  
  567.  ; Generate the HTML file.
  568.  mhh_gen_file,dict,txt_file,infiles,libfiles,outfile,verbose,title,strict
  569. END
  570.